<?php

namespace frontend\modules\shop\models;

use Yii;
use common\models\shop\ShopCart;
use common\models\shop\ShopGoods;
use common\models\shop\ShopProduct;
use common\models\shop\ShopOrder;
use common\models\shop\ShopOrderGoods;
use common\models\shop\ShopOrderDiscount;
use common\logics\DiscountLogic;
use common\helpers\ArrayHelper;
use common\models\shop\ShopGoodsStock;
use common\models\trade\Partner;
use common\models\user\UserAddress;
use common\models\freight\FreightReceiver;
use common\logics\ExpressCalculator;

/**
 * 用户下单模型
 * 
 * @author emhome<emhome@163.com>
 * @since 2.0
 */
class OrderForm_1 extends \common\base\Model {

    /**
     * @var integer 下单用户ID
     */
    public $user_id;

    /**
     * @var integer 收件地址ID
     */
    public $address_id;

    /**
     * @var array 折扣活动ID
     */
    public $discounts = [];

    /**
     * @var array 购物车中待结算的商品
     */
    public $carts = [];

    /**
     * @var null 用户收件地址
     */
    private $_address = null;

    /**
     * @var array 购物车数据
     */
    private $_carts = [];

    /**
     * 请求参数校验
     * @inheritdoc
     */
    public function rules() {
        return [
            [['user_id', 'carts', 'address_id'], 'required'],
            ['carts', 'validateCarts'],
            ['address_id', 'validateAddress'],
            ['discounts', 'validateDiscounts'],
        ];
    }

    /**
     * 校验购物车中的商品
     * @param string $attribute the attribute currently being validated
     */
    public function validateCarts($attribute) {
        if ($this->hasErrors()) {
            return;
        }
        $cartIds = $this->$attribute;
        if (!empty($cartIds)) {
            $carts = $this->getCartData();
            $realCarts = ArrayHelper::getColumn($carts, 'id');
            if (array_diff($realCarts, $cartIds)) {
                $this->addError($attribute, '所购商品状态已发生变化');
            }
        } else {
            $this->addError($attribute, '未提交任何待结算商品信息');
        }
    }

    /**
     * 校验收件地址
     * @param string $attribute the attribute currently being validated
     */
    public function validateAddress($attribute) {
        if ($this->hasErrors()) {
            return;
        }
        if ($this->getAddress() == null) {
            $this->addError($attribute, '未找到当前选择的收件地址信息');
        }
    }

    /**
     * 校验优惠信息
     * @param string $attribute the attribute currently being validated
     */
    public function validateDiscounts($attribute) {
        if ($this->hasErrors()) {
            return;
        }
    }

    /**
     * 获取用户收件地址
     * @return UserAddress|null
     */
    protected function getAddress() {
        if ($this->_address === null) {
            $this->_address = UserAddress::find()->where([
                'id' => $this->address_id,
                'user_id' => $this->user_id,
            ])->one();
        }
        return $this->_address;
    }

    /**
     * 设置购物车数据
     * @return \common\models\trade\Partner|null
     */
    protected function setCartData() {
        $this->_carts = ShopCart::waitBalance($this->user_id, $this->carts);
    }

    /**
     * 获取购物车数据
     * @return \common\models\trade\Partner|null
     */
    protected function getCartData() {
        if (empty($this->_carts)) {
            $this->setCartData();
        }
        return $this->_carts;
    }

    /**
     * 订单下单保存
     */
    public function save() {
        if (!$this->validate()) {
            return $this->dumpError('下单失败');
        }
        $carts = $this->getCartData();

        $dislogic = new DiscountLogic($carts);
        $goods = $dislogic->reckon();

        $amount = 0;
        $discount = 0;
        $goodsAttributes = [];
        foreach ($goods as $gid => $ginfo) {
            $_amount = $ginfo['price'] * $ginfo['number'];
            $_discount = $_amount - $ginfo['subtotal'];
            $goodsAttributes[] = [
                'product_id' => $ginfo['product_id'],
                'name' => $ginfo['product_name'],
                'goods_id' => $gid,
                'goods_name' => $ginfo['name'],
                'goods_cover' => $ginfo['cover'],
                'goods_code' => $ginfo['code'],
                'goods_price' => $ginfo['price'],
                'goods_discount' => $_discount,
                'goods_number' => $ginfo['number'],
            ];
            $amount += $_amount;
            $discount += $_discount;
        }

        //设置订单收件信息
        $address = $this->getAddress();

        $receiver = new FreightReceiver();
        $receiver->attributes = [
            'user_id' => $address->user_id,
            'original_id' => $address->id,
            'name' => $address->name,
            'mobile' => $address->mobile,
            'province' => $address->province,
            'city' => $address->city,
            'district' => $address->district,
            'address' => $address->address_detail,
            'area_code' => $address->area_code,
            'postal_code' => $address->postal_code,
        ];

        //邮费计算
        $calcexpress = new ExpressCalculator();
        $calcexpress->setAttributes([
            'items' => [],
            'areacode' => $address->area_code,
        ]);
        $express = $calcexpress->reckon();

        //创建交易
        $order = new ShopOrder();
        $order->attributes = [
            'user_id' => $this->user_id,
            'amount' => $amount,
            'discount' => $discount,
            'pay' => $amount - $discount,
            'status' => ShopOrder::STATUS_DEFAULT,
        ];
        $order->generateNo();

        //开启事务
        $transaction = Yii::$app->db->beginTransaction();
        try {
            if (!$receiver->save()) {
                throw new Exception('收件信息保存失败！');
            }
            $order->receiver_id = $receiver->id;
            if (!$order->save()) {
                throw new Exception('交易创建失败！');
            }
            $orderId = $order->id;
            $orderGoods = new ShopOrderGoods();
            foreach ($goodsAttributes as $_attributes) {
                $_model = clone $orderGoods;
                $_model->setAttributes($_attributes);
                $_model->order_id = $orderId;
                if (!$_model->save()) {
                    throw new Exception('交易创建失败！');
                }
                $changed = ShopGoodsStock::reduce($_model->goods_id, $_model->goods_number);
                if (!$changed) {
                    throw new Exception('库存分配失败！');
                }
            }

            $transaction->commit();
        } catch (Exception $e) {
            $transaction->rollBack();
            $this->dumpError($e->getMessage());
        }

        //创建自动过期任务队列
        $taskid = Yii::$app->queue->delay($order->countdown)->push(new \common\jobs\ShopOrderExpiredJob([
            'order_id' => $order->id
        ]));
        Yii::$app->cache->set('queue_shop_order_' . $order->id, $taskid);

        $cartids = ArrayHelper::getColumn($carts, 'id');
        ShopCart::deleteAll(['id' => $cartids]);

        return $order;
    }

    public function formatList($list) {
        $data = [];
        foreach ($list as $model) {
            $goods = $model->goods;
            if (!$goods) {
                continue;
            }
            $data[$model->goods_id] = [
                'id' => $model->goods_id,
                'product_id' => $goods->product_id,
                'product_name' => $goods->product->name,
                'name' => $goods->name,
                'cover' => $goods->cover ?: $goods->product->cover,
                'code' => $goods->goods_no,
                'price' => $goods->price,
                'number' => $model->num,
                'discount' => $goods->discount,
                'type_id' => $model->product->type_id,
                'brand_id' => $model->product->brand_id,
                'subtotal' => ($goods->price - $goods->discount) * $model->num,
            ];
        }
        return $data;
    }

}
